# -*- coding: utf-8 -*-
import os
import sqlite3
from tkinter import *
from tkinter import messagebox

class Book:
    def __init__(self, title, author, isbn, available=True, category_id=None):
        self.title = title
        self.author = author
        self.isbn = isbn
        self.available = available
        self.category_id = category_id

    def __str__(self):
        return f'书名：{self.title}\n作者：{self.author}\nISBN：{self.isbn}\n状态：{"可借阅" if self.available else "已借出"}'

class Library:
    def __init__(self, db_path='library.db'):
        self.conn = sqlite3.connect(db_path)
        self._init_db()
        self.categories = self._load_categories()
        self.books = self._load_books()  # 初始化时加载图书数据

    def _init_db(self):
        # 创建分类表（文件夹层级结构）
        self.conn.execute('''CREATE TABLE IF NOT EXISTS categories (
                            id INTEGER PRIMARY KEY AUTOINCREMENT,
                            name TEXT NOT NULL,
                            parent_id INTEGER,
                            FOREIGN KEY(parent_id) REFERENCES categories(id))''')
        # 创建图书表（关联分类）
        self.conn.execute('''CREATE TABLE IF NOT EXISTS books (
                            isbn TEXT PRIMARY KEY,
                            title TEXT NOT NULL,
                            author TEXT NOT NULL,
                            available BOOLEAN DEFAULT TRUE,
                            category_id INTEGER,
                            FOREIGN KEY(category_id) REFERENCES categories(id))''')
        # 创建借阅记录表
        self.conn.execute('''CREATE TABLE IF NOT EXISTS borrow_records (
                            id INTEGER PRIMARY KEY AUTOINCREMENT,
                            isbn TEXT NOT NULL,
                            borrower TEXT NOT NULL,
                            borrow_date TEXT NOT NULL,
                            return_date TEXT,
                            FOREIGN KEY(isbn) REFERENCES books(isbn))''')
        self.conn.commit()

    def _load_categories(self):
        cursor = self.conn.execute('SELECT id, name, parent_id FROM categories')
        return [{'id': row[0], 'name': row[1], 'parent_id': row[2]} for row in cursor.fetchall()]

    def _load_books(self):
        cursor = self.conn.execute('SELECT isbn, title, author, available, category_id FROM books')
        return [Book(title=row[1], author=row[2], isbn=row[0], available=row[3]) for row in cursor.fetchall()]

    def add_category(self, name, parent_id=None):
        try:
            self.conn.execute('INSERT INTO categories (name, parent_id) VALUES (?, ?)', (name, parent_id))
            self.conn.commit()
            self.categories = self._load_categories()
            return True, '分类添加成功'
        except sqlite3.Error as e:
            return False, f'添加分类失败：{str(e)}'

    def get_category_tree(self):
        tree = {None: []}
        for cat in self.categories:
            if cat['parent_id'] not in tree:
                tree[cat['parent_id']] = []
            tree[cat['parent_id']].append(cat)
        return tree

    def add_book(self, book, category_id=None):
        try:
            self.conn.execute('''INSERT INTO books (isbn, title, author, available, category_id)
                                VALUES (?, ?, ?, ?, ?)''',
                             (book.isbn, book.title, book.author, book.available, category_id))
            self.conn.commit()
            return True, '图书添加成功！'
        except sqlite3.IntegrityError:
            return False, '该ISBN已存在'

    def remove_book(self, isbn):
        cursor = self.conn.execute('DELETE FROM books WHERE isbn = ?', (isbn,))
        if cursor.rowcount == 0:
            return False, '未找到该ISBN的图书'
        self.conn.commit()
        self.books = self._load_books()  # 重新加载图书数据
        return True, '图书删除成功！'

    def search_books(self, keyword):
        cursor = self.conn.execute('''SELECT isbn, title, author, available FROM books
                                      WHERE LOWER(title) LIKE ? OR LOWER(author) LIKE ?''',
                                   (f'%{keyword.lower()}%', f'%{keyword.lower()}%'))
        return [Book(title=row[1], author=row[2], isbn=row[0], available=row[3]) for row in cursor.fetchall()]

    def borrow_book(self, isbn, borrower):
        # 检查图书是否存在且可借
        cursor = self.conn.execute('SELECT available FROM books WHERE isbn = ?', (isbn,))
        result = cursor.fetchone()
        if not result:
            return False, '图书不存在'
        if not result[0]:
            return False, '图书已被借出'
        
        # 更新图书状态
        self.conn.execute('UPDATE books SET available = FALSE WHERE isbn = ?', (isbn,))
        
        # 添加借阅记录
        from datetime import datetime
        borrow_date = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        self.conn.execute('''INSERT INTO borrow_records (isbn, borrower, borrow_date)
                            VALUES (?, ?, ?)''', (isbn, borrower, borrow_date))
        self.conn.commit()
        return True, '借阅成功'

    def return_book(self, isbn):
        # 检查图书是否存在且已借出
        cursor = self.conn.execute('SELECT available FROM books WHERE isbn = ?', (isbn,))
        result = cursor.fetchone()
        if not result:
            return False, '图书不存在'
        if result[0]:
            return False, '图书未被借出'
        
        # 更新图书状态
        self.conn.execute('UPDATE books SET available = TRUE WHERE isbn = ?', (isbn,))
        
        # 更新借阅记录
        from datetime import datetime
        return_date = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        self.conn.execute('''UPDATE borrow_records 
                            SET return_date = ? 
                            WHERE isbn = ? AND return_date IS NULL''', 
                         (return_date, isbn))
        self.conn.commit()
        return True, '归还成功'

    def get_borrow_history(self, isbn=None):
        query = '''SELECT br.isbn, b.title, br.borrower, br.borrow_date, br.return_date 
                  FROM borrow_records br
                  JOIN books b ON br.isbn = b.isbn'''
        params = []
        if isbn:
            query += ' WHERE br.isbn = ?'
            params.append(isbn)
        query += ' ORDER BY br.borrow_date DESC'
        
        cursor = self.conn.execute(query, params)
        return cursor.fetchall()

    def delete_category(self, category_id):
        # 检查是否有子分类
        cursor = self.conn.execute('SELECT COUNT(*) FROM categories WHERE parent_id = ?', (category_id,))
        if cursor.fetchone()[0] > 0:
            return False, '该分类下还有子分类，无法删除'
            
        # 检查是否有图书
        cursor = self.conn.execute('SELECT COUNT(*) FROM books WHERE category_id = ?', (category_id,))
        if cursor.fetchone()[0] > 0:
            return False, '该分类下还有图书，无法删除'
            
        # 删除分类
        self.conn.execute('DELETE FROM categories WHERE id = ?', (category_id,))
        self.conn.commit()
        self.categories = self._load_categories()
        return True, '分类删除成功'

class LibraryApp:
    def __init__(self, root):
        self.root = root
        self.root.title('图书馆分类浏览')
        self.root.geometry('946x637')
        self.root.configure(bg='#f0f0f0')  # 设置背景色
        
        # 定义样式
        self.style = {
            'bg': '#f0f0f0',  # 背景色
            'button_bg': '#ffffff',  # 按钮背景色
            'button_fg': '#333333',  # 按钮文字颜色
            'button_active_bg': '#e6e6e6',  # 按钮按下时的背景色
            'button_active_fg': '#000000',  # 按钮按下时的文字颜色
            'button_font': ('微软雅黑', 10),  # 按钮字体
            'title_font': ('微软雅黑', 12, 'bold'),  # 标题字体
            'text_font': ('微软雅黑', 10),  # 文本字体
            'button_width': 20,  # 按钮宽度
            'button_height': 2,  # 按钮高度
            'padding': 5,  # 内边距
        }

        self.library = Library()
        self.current_parent_id = None
        self.parent_stack = []
        self.selected_category_id = None
        self.cat_btns = {}
        self.folder_icon = '📁'
        self.path_buttons = []

        # 创建右键菜单
        self.context_menu = Menu(self.root, tearoff=0)
        self.category_menu = Menu(self.root, tearoff=0)
        self.book_menu = Menu(self.root, tearoff=0)

        # 设置菜单样式
        for menu in [self.context_menu, self.category_menu, self.book_menu]:
            menu.configure(
                bg=self.style['button_bg'],
                fg=self.style['button_fg'],
                activebackground=self.style['button_active_bg'],
                activeforeground=self.style['button_active_fg'],
                font=self.style['text_font']
            )

        # 空白处菜单
        self.context_menu.add_command(label="新建分类", command=self.add_category)
        self.context_menu.add_command(label="新建图书", command=self.add_book)

        # 分类菜单
        self.category_menu.add_command(label="新建分类", command=self.add_category)
        self.category_menu.add_command(label="删除分类", command=self.delete_category)
        self.category_menu.add_command(label="新建图书", command=self.add_book)

        # 图书菜单
        self.book_menu.add_command(label="删除图书", command=self.delete_book)
        self.book_menu.add_command(label="借出图书", command=self.borrow_book)
        self.book_menu.add_command(label="归还图书", command=self.return_book)

        # 添加分类路径显示框架
        self.path_frame = Frame(self.root, bg=self.style['bg'])
        self.path_frame.grid(row=0, column=0, sticky='ew', padx=10, pady=10)
        Label(self.path_frame, text="当前位置：", font=self.style['text_font'], bg=self.style['bg']).pack(side='left')
        self.path_buttons_frame = Frame(self.path_frame, bg=self.style['bg'])
        self.path_buttons_frame.pack(side='left', fill='x', expand=True)

        self.category_grid_frame = Frame(self.root, bg=self.style['bg'])
        self.category_grid_frame.grid(row=1, column=0, sticky='nsew', padx=10, pady=10)
        self.root.grid_rowconfigure(1, weight=1)
        self.root.grid_columnconfigure(0, weight=1)

        self.category_grid_frame.bind("<Button-3>", self.show_context_menu)
        self.root.bind('<Delete>', self.on_delete_key)

        self.show_category_grid(self.current_parent_id)

    def _check_category_operation(self, operation_name):
        """检查分类操作的基本条件"""
        has_subcategories = any(cat['parent_id'] == self.current_parent_id for cat in self.library.categories)
        if has_subcategories:
            messagebox.showwarning('警告', f'只能在最底层分类中{operation_name}！')
            return False
        if not self.current_parent_id:
            messagebox.showwarning('警告', '请先进入某个分类并显示图书列表！')
            return False
        return True

    def _get_selected_book(self, operation_name):
        """获取选中的图书信息"""
        if not self._check_category_operation(operation_name):
            return None
        selected_items = self.book_tree.selection()
        if not selected_items:
            messagebox.showwarning('警告', f'请先选择要{operation_name}的图书！')
            return None
        selected_item = selected_items[0]
        values = self.book_tree.item(selected_item)['values']
        return {'title': values[0], 'isbn': values[2], 'status': values[3]}

    def show_context_menu(self, event):
        """根据点击位置显示不同的右键菜单"""
        # 检查是否点击在图书列表上
        if hasattr(self, 'book_tree'):
            item = self.book_tree.identify_row(event.y)
            if item:
                # 选中该图书
                self.book_tree.selection_set(item)
                self.book_menu.post(event.x_root, event.y_root)
                return

        # 检查是否点击在分类按钮上
        for category_id, btn in self.cat_btns.items():
            if btn.winfo_containing(event.x_root, event.y_root):
                self.selected_category_id = category_id
                self.category_menu.post(event.x_root, event.y_root)
                return

        # 如果都不是，显示空白处菜单
        self.context_menu.post(event.x_root, event.y_root)

    def show_category_grid(self, parent_id):
        """显示分类网格"""
        # 清除现有内容
        for widget in self.category_grid_frame.winfo_children():
            widget.destroy()
        self.cat_btns.clear()

        self.current_parent_id = parent_id
        self.update_path_display()

        # 获取当前分类下的子分类
        categories = [cat for cat in self.library.categories if cat['parent_id'] == parent_id]
        
        if not categories:
            self.show_books_in_category(parent_id)
            return

        # 创建分类网格
        self.create_category_grid(categories)

    def update_path_display(self):
        # 清除现有的路径按钮
        for btn in self.path_buttons:
            btn.destroy()
        self.path_buttons.clear()

        # 添加根目录按钮
        root_btn = Button(self.path_buttons_frame, 
                         text="根目录",
                         font=self.style['text_font'],
                         bg=self.style['button_bg'],
                         fg=self.style['button_fg'],
                         activebackground=self.style['button_active_bg'],
                         activeforeground=self.style['button_active_fg'],
                         relief='flat',
                         cursor='hand2',
                         command=lambda: self.navigate_to_category(None))
        root_btn.pack(side='left')
        self.path_buttons.append(root_btn)

        if self.current_parent_id is None:
            return

        # 构建分类路径
        path = []
        current_id = self.current_parent_id
        while current_id is not None:
            category = next((cat for cat in self.library.categories if cat['id'] == current_id), None)
            if category:
                path.insert(0, category)
                current_id = category['parent_id']
            else:
                break

        # 为每个分类创建按钮
        for category in path:
            # 添加分隔符
            separator = Label(self.path_buttons_frame, 
                            text=" > ",
                            font=self.style['text_font'],
                            bg=self.style['bg'],
                            fg=self.style['button_fg'])
            separator.pack(side='left')
            self.path_buttons.append(separator)

            # 添加分类按钮
            btn = Button(self.path_buttons_frame, 
                        text=category['name'],
                        font=self.style['text_font'],
                        bg=self.style['button_bg'],
                        fg=self.style['button_fg'],
                        activebackground=self.style['button_active_bg'],
                        activeforeground=self.style['button_active_fg'],
                        relief='flat',
                        cursor='hand2',
                        command=lambda cid=category['id']: self.navigate_to_category(cid))
            btn.pack(side='left')
            self.path_buttons.append(btn)

    def navigate_to_category(self, category_id):
        """导航到指定分类"""
        if category_id == self.current_parent_id:
            return
            
        # 清除搜索框内容和搜索状态
        if hasattr(self, 'search_var'):
            self.search_var.set('')
        if hasattr(self, 'is_search_mode'):
            self.is_search_mode = False
            self.search_keyword = None
            
        # 显示分类网格
        self.show_category_grid(category_id)

    def on_category_click(self, category_id):
        # 单击高亮
        if self.selected_category_id and self.selected_category_id in self.cat_btns:
            self.cat_btns[self.selected_category_id].config(bg=self.style['button_bg'])
        self.selected_category_id = category_id
        self.cat_btns[category_id].config(bg='#e6f2ff')  # 选中时的背景色

    def on_category_double_click(self, category_id):
        self.show_category_grid(category_id)

    def on_category_right_click(self, event, category_id):
        """处理分类按钮右键点击事件"""
        self.on_category_click(category_id)
        self.category_menu.post(event.x_root, event.y_root)

    def on_delete_category_click(self, category_id):
        """处理删除分类按钮点击事件"""
        if messagebox.askyesno('确认删除', '确定要删除该分类吗？'):
            success, msg = self.library.delete_category(category_id)
            if not success:
                messagebox.showwarning('警告', msg)
            # 删除分类后刷新当前分类的视图
            self.show_category_grid(self.current_parent_id)

    def add_category(self):
        # 计算新分类的位置
        subcats = [cat for cat in self.library.categories if cat['parent_id'] == self.current_parent_id]
        max_width = 946 - 40  # 主窗口宽度减去边距
        btn_width = 180  # 每个按钮实际宽度（含padding）
        per_row = max(1, max_width // btn_width)
        row = len(subcats) // per_row
        col = len(subcats) % per_row

        # 找到buttons_frame
        buttons_frame = None
        for widget in self.category_grid_frame.winfo_children():
            if isinstance(widget, Frame):
                buttons_frame = widget
                break
        if buttons_frame is None:
            buttons_frame = self.category_grid_frame

        # 直接在buttons_frame里用grid布局
        icon_entry_frame = Frame(buttons_frame)
        icon_entry_frame.grid(row=row, column=col, padx=20, pady=20)

        # 分类图标
        icon_label = Label(icon_entry_frame, text=self.folder_icon, font=('微软雅黑', 36), bg='#e6f2ff', width=4, height=2)
        icon_label.pack()

        # 蓝色高亮输入框
        entry = Entry(icon_entry_frame, font=('微软雅黑', 14), width=16, relief='solid', bd=2, highlightthickness=2, highlightbackground='#0078d7', highlightcolor='#0078d7')
        entry.pack(pady=(2,0))
        entry.focus_set()

        def on_ok(event=None):
            name = entry.get().strip()
            if name:
                success, msg = self.library.add_category(name, self.current_parent_id)
                if not success:
                    messagebox.showwarning('警告', msg)
                else:
                    # 刷新当前分类视图
                    self.show_category_grid(self.current_parent_id)
            icon_entry_frame.destroy()

        def on_cancel(event=None):
            icon_entry_frame.destroy()

        entry.bind('<Return>', on_ok)
        entry.bind('<Escape>', on_cancel)
        entry.bind('<FocusOut>', on_cancel)

    def delete_category(self):
        if not self.selected_category_id:
            messagebox.showwarning('警告', '请先单击选中要删除的分类！')
            return
        if messagebox.askyesno('确认', '确定要删除该分类吗？'):
            success, msg = self.library.delete_category(self.selected_category_id)
            if not success:
                messagebox.showwarning('警告', msg)
            # 删除分类后刷新当前分类的视图
            self.show_category_grid(None)

    def show_books_in_category(self, category_id):
        """显示指定分类下的图书"""
        # 清除现有的所有内容
        for widget in self.category_grid_frame.winfo_children():
            widget.destroy()

        # 更新当前父分类ID
        self.current_parent_id = category_id
        
        # 更新分类路径显示
        self.update_path_display()

        # 获取该分类下的所有图书
        cursor = self.library.conn.execute('SELECT isbn, title, author, available FROM books WHERE category_id = ?', (category_id,))
        books = cursor.fetchall()

        if not books:
            # 如果没有图书，显示提示信息
            label = Label(self.category_grid_frame, 
                         text='该分类下没有图书', 
                         font=self.style['title_font'],
                         bg=self.style['bg'],
                         fg='#666666')
            label.grid(row=0, column=0, pady=50)
            return

        # 创建图书列表
        from tkinter import ttk
        style = ttk.Style()
        style.configure("Treeview",
                       background=self.style['button_bg'],
                       foreground=self.style['button_fg'],
                       fieldbackground=self.style['button_bg'],
                       font=self.style['text_font'])
        style.configure("Treeview.Heading",
                       font=self.style['text_font'],
                       background=self.style['button_bg'],
                       foreground=self.style['button_fg'])

        self.book_tree = ttk.Treeview(self.category_grid_frame, 
                                    columns=('title', 'author', 'isbn', 'status'),
                                    show='headings',
                                    style="Treeview")
        self.book_tree.heading('title', text='书名')
        self.book_tree.heading('author', text='作者')
        self.book_tree.heading('isbn', text='ISBN')
        self.book_tree.heading('status', text='状态')
        self.book_tree.column('title', width=200)
        self.book_tree.column('author', width=120)
        self.book_tree.column('isbn', width=150)
        self.book_tree.column('status', width=80)
        self.book_tree.grid(row=0, column=0, padx=20, pady=20, sticky='nsew')
        
        # 添加滚动条
        scrollbar = ttk.Scrollbar(self.category_grid_frame, orient="vertical", command=self.book_tree.yview)
        scrollbar.grid(row=0, column=1, sticky='ns')
        self.book_tree.configure(yscrollcommand=scrollbar.set)

        # 添加图书到列表
        for book in books:
            status = '可借阅' if book[3] else '已借出'
            self.book_tree.insert('', 'end', values=(book[1], book[2], book[0], status))

        # 绑定右键菜单和Delete键
        self.book_tree.bind('<Button-3>', self.show_context_menu)
        self.book_tree.bind('<Delete>', self.on_delete_key)

    def add_book(self):
        # 检查当前分类是否有子分类
        has_subcategories = any(cat['parent_id'] == self.current_parent_id for cat in self.library.categories)
        if has_subcategories:
            messagebox.showwarning('警告', '只能在最底层分类中添加图书！')
            return

        if not self.current_parent_id:
            messagebox.showwarning('警告', '请先进入某个分类！')
            return

        dialog = Toplevel(self.root)
        dialog.title('添加图书')
        dialog.transient(self.root)
        dialog.grab_set()

        Label(dialog, text='书名：').pack(pady=5)
        title_entry = Entry(dialog)
        title_entry.pack(pady=5)

        Label(dialog, text='作者：').pack(pady=5)
        author_entry = Entry(dialog)
        author_entry.pack(pady=5)

        Label(dialog, text='ISBN：').pack(pady=5)
        isbn_entry = Entry(dialog)
        isbn_entry.pack(pady=5)

        def on_ok():
            title = title_entry.get().strip()
            author = author_entry.get().strip()
            isbn = isbn_entry.get().strip()
            if not all([title, author, isbn]):
                messagebox.showwarning('警告', '所有字段不能为空！')
                return
            success, msg = self.library.add_book(Book(title, author, isbn, category_id=self.current_parent_id), self.current_parent_id)
            messagebox.showinfo('提示', msg)
            dialog.destroy()
            self.show_books_in_category(self.current_parent_id)

        Button(dialog, text='确定', command=on_ok).pack(pady=10)

    def delete_book(self):
        book = self._get_selected_book('删除')
        if not book:
            return

        if messagebox.askyesno('确认删除', f'确定要删除 "{book["title"]}" 这本书吗？'):
            success, msg = self.library.remove_book(book['isbn'])
            messagebox.showinfo('提示', msg)
            self.show_books_in_category(self.current_parent_id)

    def on_delete_key(self, event):
        """处理Delete键按下事件"""
        try:
            if hasattr(self, 'book_tree') and self.book_tree.winfo_exists() and self.book_tree.selection():
                self.delete_book()
            elif self.selected_category_id:
                self.delete_category()
        except Exception:
            # 如果book_tree已经被销毁，忽略错误
            pass

    def borrow_book(self):
        book = self._get_selected_book('借出')
        if not book or book['status'] != '可借阅':
            messagebox.showwarning('警告', '该图书已被借出！')
            return

        dialog = Toplevel(self.root)
        dialog.title('借出图书')
        dialog.transient(self.root)
        dialog.grab_set()

        Label(dialog, text=f'书名：{book["title"]}').pack(pady=5)
        Label(dialog, text='借阅人：').pack(pady=5)
        borrower_entry = Entry(dialog)
        borrower_entry.pack(pady=5)
        borrower_entry.focus_set()

        def on_ok():
            borrower = borrower_entry.get().strip()
            if not borrower:
                messagebox.showwarning('警告', '请输入借阅人姓名！')
                return
            success, msg = self.library.borrow_book(book['isbn'], borrower)
            messagebox.showinfo('提示', msg)
            dialog.destroy()
            self.show_books_in_category(self.current_parent_id)

        Button(dialog, text='确定', command=on_ok).pack(side='left', padx=20, pady=10)
        Button(dialog, text='取消', command=dialog.destroy).pack(side='left', padx=20, pady=10)
        dialog.bind('<Return>', lambda e: on_ok())
        dialog.bind('<Escape>', lambda e: dialog.destroy())

    def return_book(self):
        book = self._get_selected_book('归还')
        if not book or book['status'] != '已借出':
            messagebox.showwarning('警告', '该图书未被借出！')
            return

        if messagebox.askyesno('确认归还', f'确定要归还 "{book["title"]}" 这本书吗？'):
            success, msg = self.library.return_book(book['isbn'])
            messagebox.showinfo('提示', msg)
            self.show_books_in_category(self.current_parent_id)

    def show_search_results(self, books, keyword):
        """显示搜索结果"""
        # 清除现有内容
        for widget in self.category_grid_frame.winfo_children():
            widget.destroy()

        # 标题
        title_label = Label(self.category_grid_frame, 
                          text=f"🔍 搜索结果：'{keyword}' ({len(books)} 本图书)", 
                          font=self.style['title_font'], bg=self.style['bg'], 
                          fg=self.style['button_fg'])
        title_label.grid(row=0, column=0, columnspan=2, pady=(0, 20), sticky='w')

        # 创建图书列表
        book_data = [(book.title, book.author, book.isbn, book.available) for book in books]
        self.create_modern_book_list(book_data)
        
        # 保存当前搜索状态
        self.is_search_mode = True
        self.search_keyword = keyword

if __name__ == '__main__':
    try:
        root = Tk()
        app = LibraryApp(root)
        root.mainloop()
    except Exception as e:
        print(f"发生错误: {e}")
